package cn.mw.cmdb.processor.zabbix;

import cn.mw.cmdb.entity.InstanceInfo;
import cn.mw.cmdb.enums.MonitorModeType;
import cn.mw.cmdb.exception.FindNoException;
import cn.mw.cmdb.param.zabbixResult.ItemApplication;
import cn.mw.cmdb.processor.Macros;
import cn.mw.cmdb.processor.MonitorParamContext;
import cn.mw.cmdb.processor.MonitorValue;
import cn.mw.microMonitorCommon.entity.zabbix.HostCreateParam;
import cn.mw.microMonitorCommon.enums.SecurityLevel;
import cn.mw.microMonitorCommon.enums.SecurityProtocolType;
import cn.mw.microMonitorCommon.util.ListMapObjUtils;
import cn.mw.microMonitorCommon.util.MD5Utils;
import cn.mw.microMonitorCommon.util.RSAUtils;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.*;

import static cn.mw.cmdb.enums.MonitorModeType.getMonitorName;
import static cn.mw.cmdb.processor.MonitorValue.defaultMarcos;
import static cn.mw.cmdb.service.impl.AssetsManageServiceImpl.*;
import static cn.mw.cmdb.util.ValConvertUtil.intValueConvert;
import static cn.mw.cmdb.util.ValConvertUtil.strValueConvert;

@Component
@Slf4j
public class ZabbixUtils {
    private String typeKey = "type";
    private String valueKey = "value";
    private String macroKey = "macro";
    private String VCENTER_HOST_KEY = "{$VCENTER_HOST}";
    private String HTTPS_KEY = "https://";
    private String VCENTER_SDK = "/sdk";



    public HostCreateParam transform(MonitorValue monitorValue, MonitorParamContext context) {
        HostCreateParam hostCreateParam = new HostCreateParam();
        InstanceInfo instanceInfo = new InstanceInfo();
        if (monitorValue instanceof InstanceInfo) {
            instanceInfo = (InstanceInfo) monitorValue;
        }
        //zabbix主机名称为了保证唯一性,使用uuid + 时间生成的md5编码
        //同时为了方便运维人员根据页面的实例名称查找相关信息,需要把name设置为实例名称 + uuid
        String host = MD5Utils.md5Hex(UUID.randomUUID().toString() + new Date().getTime(), "utf-8");
        if (monitorValue.getRandomNameKey()) {
            hostCreateParam.setHost(host);
        } else {
            hostCreateParam.setHost(!Strings.isNullOrEmpty(strValueConvert(monitorValue.getHostName()))?monitorValue.getHostName():monitorValue.getInstanceName());
        }
        String name = monitorValue.getInstanceName() + host;
        hostCreateParam.setName(name);
        ZabbixConvert zabbixConvert = new ZabbixConvert();
        zabbixConvert.setContext(context);
        zabbixConvert.setMonitorValue(monitorValue);
        //获取分组Id
        ArrayList<String> groupIdList = new ArrayList<>();
        if (context.getMapParam() != null && context.getMapParam().get(GROUP_MAP_KEY) != null) {
            //批量纳管参数转换
            Map<String, Object> groupMapById = (Map<String, Object>) context.getMapParam().get(GROUP_MAP_KEY);
            groupIdList.add(strValueConvert(groupMapById.get(instanceInfo.getGroupId())));
        } else {
            groupIdList.add(monitorValue.getHostGroupId().toString());
        }
        if (CollectionUtils.isEmpty(groupIdList)) {
            throw new FindNoException("find-no-group-error");
        }
        ArrayList<Map<String, Object>> interList = new ArrayList<>();
        Map interMap = new HashMap();
        interMap.put("ip", monitorValue.getInBandIp());
        interMap.put("main", 1);
        String port = (null != monitorValue.getPort() ? monitorValue.getPort().toString() : "");
        String community = "";
        List<Map> macroDTOS = new ArrayList<>();
        Map detailsMap = new HashMap();
        List macroList = monitorValue.getMacrosList();
        if (null != macroList && macroList.size() > 0) {
            for (Object obj : macroList) {
                if (obj != null && obj instanceof Map) {
                    Map<String, Object> macroMap = (Map<String, Object>) obj;
                    Macros macro = JSONObject.parseObject(JSONObject.toJSONString(obj), Macros.class);
                    //type为1，表示密文需要解密
                    if (intValueConvert(macroMap.get(typeKey)) == 1) {
                        macroMap.put(valueKey,RSAUtils.decryptData(strValueConvert(macroMap.get(valueKey)), RSAUtils.RSA_PRIVATE_KEY));
                    }
                    //如果是虚拟化主机Ip宏值：{$VCENTER_HOST}，需要自动补齐https://ip/sdk
                    if (macroMap.get(macroKey)!=null && VCENTER_HOST_KEY.equals(macroMap.get(macroKey)) && macroMap.get(valueKey)!=null ) {
                        Object ip = macroMap.get(valueKey);
                        String ipMacro = HTTPS_KEY + ip + VCENTER_SDK;
                        macroMap.put(valueKey,ipMacro);
                    }
                    if (macroMap.get(macroKey)!=null && macroMap.get(valueKey)==null) {
                        macroMap.put(valueKey,"");
                    }
                    macroDTOS.add(macroMap);
                }

            }
        }
        //获取实例id,添加到主机宏值中，方便告警管理通过实例id关联资产信息
        Map macroMap = new HashMap();
        macroMap.put("macro", defaultMarcos);
        macroMap.put("value", monitorValue.getId());
        macroDTOS.add(macroMap);
        String userName = "";
        String passWord = "";


        String monitorType = !Strings.isNullOrEmpty(monitorValue.getRuleType()) ? monitorValue.getRuleType() : getMonitorName(monitorValue.getMonitorMode());

        MonitorModeType ruleType = MonitorModeType.valueOf(monitorType);
        if (monitorValue instanceof InstanceInfo && ((InstanceInfo) monitorValue).getData() != null) {
            log.info("monitorValue.getData()::" + ((InstanceInfo) monitorValue).getData());
        }
        //使用默认端口
        int interfaceType = (monitorValue.getInterfacesType() != null && monitorValue.getInterfacesType() > 0) ? monitorValue.getInterfacesType() : ruleType.geInterfaceType();
        int snmpv1v2Version = 2;
        if (MonitorModeType.SNMPv1 == ruleType) {
            snmpv1v2Version = 1;
        }

        switch (ruleType) {
            case SNMP:
            case SNMPv1:
            case SNMPv2:
                community = monitorValue.getCommunity();

                detailsMap.put("version", snmpv1v2Version);
                detailsMap.put("bulk", 1);
                detailsMap.put("community", community);

                Map map = new HashMap();
                map.put("macro", "{$SNMP_COMMUNITY}");
                map.put("value", community);
                if (null == macroDTOS) {
                    macroDTOS = new ArrayList<>();
                }
                macroDTOS.add(map);
                break;
            case SNMPv3:
                detailsMap.put("version", 3);
                detailsMap.put("bulk", 1);
                detailsMap.put("securityname", monitorValue.getSecurityName());
                SecurityLevel securityLevel = SecurityLevel.valueOf(monitorValue.getSecurityLevel());
                detailsMap.put("securitylevel", securityLevel.getCode());
                detailsMap.put("contextname", monitorValue.getContextName());

                switch (securityLevel) {
                    case noAuthNoPriv:
                        break;
                    case authPriv:
                        SecurityProtocolType authType = SecurityProtocolType.valueOf(monitorValue.getAuthAlgName());
                        SecurityProtocolType privType = SecurityProtocolType.valueOf(monitorValue.getPrivAlgName());
                        //验证协议、验证算法
                        detailsMap.put("authprotocol", authType.getInterfaceCode());
                        //隐私协议、加密算法
                        detailsMap.put("privprotocol", privType.getInterfaceCode());
                        //验证口令
                        detailsMap.put("authpassphrase", monitorValue.getAuthValue());
                        //私钥
                        detailsMap.put("privpassphrase", monitorValue.getPriValue());
                        break;
                    case authNoPriv:
                        SecurityProtocolType authType1 = SecurityProtocolType.valueOf(monitorValue.getAuthAlgName());
                        detailsMap.put("authprotocol", authType1.getInterfaceCode());
                        detailsMap.put("authpassphrase", monitorValue.getAuthValue());
                        break;
                    default:
                }
            case IPMI:
                userName = monitorValue.getAccount();
                passWord = monitorValue.getPassword();
                break;
            default:
                log.warn("no match MonitorMode" + ruleType.getMonitorMode());
        }

        interMap.put("dns", "");
        interMap.put("port", port);
        interMap.put("type", interfaceType);//type 接口类型  1 - agent 2 - SNMP;3 - IPMI;4 - JMX.
        interMap.put("useip", 1);//使用的链接方式 0 DNS名称连接 1 IP地址进行连接
        if (detailsMap.size() > 0) {
            interMap.put("details", detailsMap);
        }
        interList.add(interMap);
        ArrayList<String> templList = new ArrayList<>();
        if (context.getMapParam() != null && context.getMapParam().get(TEMPLATE_MAP_KEY) != null) {
            Map<String, Object> tempMapById = (Map<String, Object>) context.getMapParam().get(TEMPLATE_MAP_KEY);
            int monitorMode = ruleType.getMonitorMode();
            String key = instanceInfo.getBrandId() + ":" + instanceInfo.getSpecification() + ":" + monitorMode;
            String tempId = strValueConvert(tempMapById.get(key));
            if (!Strings.isNullOrEmpty(tempId)) {
                templList.add(tempId);
                monitorValue.setHostTemplateId(tempId);
            }
        } else {
            if (!Strings.isNullOrEmpty(monitorValue.getHostTemplateId())) {
                templList.add(monitorValue.getHostTemplateId());
            }
        }
        if (CollectionUtils.isEmpty(templList)) {
            throw new FindNoException("find-no-template-error");
        }
        Integer status = (null == monitorValue.getZabbixStatus() ? 0 : monitorValue.getZabbixStatus());
        hostCreateParam.setGroups(groupIdList);
        hostCreateParam.setInterfaces(interList);
        hostCreateParam.setTemplates(templList);
        hostCreateParam.setMacros(macroDTOS);
        hostCreateParam.setMonitorProxyType(monitorValue.getProxyType());
        hostCreateParam.setStatus(status);
        String proxyId = "";
        if (context.getMapParam() != null && context.getMapParam().get(PROXY_MAP_KEY) != null) {
            Map<String, Object> proxyMapById = (Map<String, Object>) context.getMapParam().get(PROXY_MAP_KEY);
            proxyId = strValueConvert(proxyMapById.get(instanceInfo.getPollingEngine()));
        } else {
            proxyId = context.getZabbixProxyId();
        }
        hostCreateParam.setProxyID(proxyId);
        hostCreateParam.setUserName(userName);
        hostCreateParam.setPassWord(passWord);
        return hostCreateParam;
    }


    public List<HostCreateParam> transformBatch(List<? extends MonitorValue> monitorValueList, MonitorParamContext context) {
        List<HostCreateParam> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(monitorValueList)) {
            for (int x = 0; x < monitorValueList.size(); x++) {
                monitorValueList.get(x).setBatchIndex(x);
                HostCreateParam transform = transform(monitorValueList.get(x), context);
                transform.setBatchIndex(x);
                list.add(transform);
            }
        }
        return list;
    }


    public String getChNameByMap(String name, Map<String, String> mapInfo) {
        String originalName = name;
        if (name != null && !"".equals(name)) {
            String ifName = "";
            String chName = "";
            if (name.indexOf("[") != -1) {
                ifName = name.substring(name.indexOf("["), name.indexOf("]") + 1);
//                中括号在前面
                if (name.indexOf("[") == 0) {
                    name = name.substring(name.indexOf("]") + 1);
                    String descr = mapInfo.get(name);
                    if (!Strings.isNullOrEmpty(descr)) {
                        chName = ifName + descr;
                        return chName;
                    }
                }
//                中括号在后面
                if (name.indexOf("]") == (name.length() - 1)) {
                    name = name.substring(0, name.indexOf("["));
                    String descr = mapInfo.get(name);
                    if (!Strings.isNullOrEmpty(descr)) {
                        chName = descr + ifName;
                        return chName;
                    }
                }
            } else {
                String descr = mapInfo.get(name);
                if (!Strings.isNullOrEmpty(descr)) {
                    return descr;
                }
            }
        }
        return originalName;
    }

    /**
     * 监控名称处理
     * 保留主体的监控名，去除[]接口名称数据
     *
     * @return
     */
    public List<String> itemNameSubStrConvert(List<ItemApplication> itemList) {
        List<String> itemNames = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(itemList)) {
            for (ItemApplication itemApplication : itemList) {
                String name = itemApplication.getName();
                if (!Strings.isNullOrEmpty(name)) {
                    int startIndex = name.indexOf("["), endIndex = name.indexOf("]");
                    if (startIndex != -1 && endIndex != -1) {
                        String itemName = name.substring(0, startIndex + 1) + name.substring(endIndex);
                        itemNames.add(itemName);
                    } else {
                        itemNames.add(name);
                    }
                }
            }
        }
        return itemNames;
    }


    public static String substringItemName(String str) {
        int startIndex = str.indexOf("["), endIndex = str.indexOf("]");
        if (startIndex != -1 && endIndex != -1) {
            str = str.substring(0, startIndex + 1) + str.substring(endIndex);
        }
        return str;
    }


    public class ZabbixConvert {
        private MonitorValue monitorValue;
        private MonitorParamContext context;

        public MonitorValue getMonitorValue() {
            return monitorValue;
        }

        public void setMonitorValue(MonitorValue monitorValue) {
            this.monitorValue = monitorValue;
        }

        public MonitorParamContext getContext() {
            return context;
        }

        public void setContext(MonitorParamContext context) {
            this.context = context;
        }

        public String getGroupInfoById() {
            String monitorGroupId = "";
            if (context != null && context.getMapParam().get(GROUP_MAP_KEY) != null) {
                Map<String, Object> groupMapById = (Map<String, Object>) context.getMapParam().get(GROUP_MAP_KEY);
                InstanceInfo instanceInfo = paramConvert();
                if (instanceInfo != null) {
                    monitorGroupId = strValueConvert(groupMapById.get(instanceInfo.getGroupId()));
                }

            } else {
                monitorGroupId = monitorValue.getHostGroupId().toString();
            }
            return monitorGroupId;
        }

        public String getTempInfoById() {
            String monitorTempId = "";
            if (context != null && context.getMapParam().get(TEMPLATE_MAP_KEY) != null) {
                Map<String, Object> tempMapById = (Map<String, Object>) context.getMapParam().get(TEMPLATE_MAP_KEY);
                InstanceInfo instanceInfo = paramConvert();
                if (instanceInfo != null) {
                    monitorTempId = strValueConvert(tempMapById.get(instanceInfo.getTemplateId()));
                }

            } else {
                monitorTempId = monitorValue.getHostTemplateId();
            }
            return "";
        }

        public String getProxyInfoById() {
            String proxyId = "";
            if (context != null && context.getMapParam().get(PROXY_MAP_KEY) != null) {
                Map<String, Object> proxyMapById = (Map<String, Object>) context.getMapParam().get(PROXY_MAP_KEY);
                InstanceInfo instanceInfo = paramConvert();
                if (instanceInfo != null) {
                    proxyId = strValueConvert(proxyMapById.get(instanceInfo.getPollingEngine()));
                }

            } else {
                proxyId = context.getZabbixProxyId();
            }
            return "";
        }

        private InstanceInfo paramConvert() {
            if (monitorValue instanceof InstanceInfo) {
                return (InstanceInfo) monitorValue;
            }
            return null;
        }
    }
}
